package org.jeecg.modules.system.controller;

import java.util.*;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.annotation.SkipTenant;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.DictModel;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.IpUtils;
import org.jeecg.common.util.Md5Util;
import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.modules.system.entity.LoginEmployee;
import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysEmployee;
import org.jeecg.modules.system.entity.SysPermission;
import org.jeecg.modules.system.entity.SysRolePermission;
import org.jeecg.modules.system.mapper.SysPermissionMapper;
import org.jeecg.modules.system.mapper.SysRolePermissionMapper;
import org.jeecg.modules.system.mapper.SysUserRoleMapper;
import org.jeecg.modules.system.service.ISysDepartService;
import org.jeecg.modules.system.service.ISysDictService;
import org.jeecg.modules.system.service.ISysEmployeeService;
import org.jeecg.modules.system.service.ISysLogService;
import org.jeecg.modules.system.service.ISysPermissionService;
import org.jeecg.modules.system.vo.EmployeeLoginVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

/**
 * 员工登录控制器
 */
@RestController
@RequestMapping("/sys/employeeLogin")
@Api(tags = "员工登录")
@Slf4j
public class EmployeeLoginController {

    @Autowired
    private ISysEmployeeService sysEmployeeService;

    @Autowired
    private ISysDepartService sysDepartService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private ISysBaseAPI sysBaseAPI;

    @Autowired
    private ISysLogService sysLogService;

    @Autowired
    private ISysPermissionService sysPermissionService;

    @Autowired
    private ISysDictService sysDictService;

    @Autowired
    private JeecgBaseConfig jeecgBaseConfig;

    @Autowired
    private SysPermissionMapper sysPermissionMapper;

    @Autowired
    private SysRolePermissionMapper sysRolePermissionMapper;

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    /**
     * 员工登录
     */
    @ApiOperation("员工登录")
    @PostMapping("/login")
    @SkipTenant("员工登录时跳过租户过滤，避免登录失败问题")
    public Result<JSONObject> login(@RequestBody EmployeeLoginVO loginVO, HttpServletRequest request) {
        Result<JSONObject> result = new Result<>();

        // 验证参数
        if (StringUtils.isBlank(loginVO.getEmpNo()) || StringUtils.isBlank(loginVO.getPassword())) {
            return result.error500("员工编号或密码不能为空");
        }

        // 验证验证码
        String captcha = loginVO.getCaptcha();
        if (captcha != null) {
            String lowerCaseCaptcha = captcha.toLowerCase();
            String checkKey = loginVO.getCheckKey();

            // 参考LoginController中的实现，使用MD5加密key
            String origin = lowerCaseCaptcha + checkKey + jeecgBaseConfig.getSignatureSecret();
            String realKey = Md5Util.md5Encode(origin, "utf-8");

            log.info("验证码校验，key = {}，验证码 = {}", realKey, lowerCaseCaptcha);

            Object redisCode = redisUtil.get(realKey);

            if (redisCode == null) {
                log.warn("验证码已过期，key = {}，验证码 = {}", realKey, lowerCaseCaptcha);
                return result.error500("验证码已过期");
            }

            String realCaptcha = redisCode.toString();

            if (!realCaptcha.equals(lowerCaseCaptcha)) {
                log.warn("验证码错误，key = {}，UI验证码 = {}，Redis验证码 = {}", checkKey, lowerCaseCaptcha, realCaptcha);
                return result.error500("验证码错误");
            }

            // 验证通过，删除Redis中的验证码
            redisUtil.del(realKey);
            log.info("验证码校验通过，key = {}", realKey);
        }

        // 验证员工登录
        SysEmployee employee = sysEmployeeService.checkEmployeeLogin(loginVO.getEmpNo(), loginVO.getPassword(), loginVO.getTenantId());
        if (employee == null) {
            return result.error500("员工账号或密码错误");
        }

        // 检查员工状态
        if (employee.getWorkStatus() != null && employee.getWorkStatus() != 1) {
            return result.error500("该员工已离职，无法登录");
        }

        // 生成token
        String token = JwtUtil.sign(employee.getUsername(), employee.getPassword());

        // 设置token缓存有效时间
        redisUtil.set(CommonConstant.PREFIX_EMPLOYEE_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_EMPLOYEE_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);

        // 设置登录类型为员工登录
        redisUtil.set(CommonConstant.PREFIX_EMPLOYEE_TOKEN + token + "_loginType", CommonConstant.EMPLOYEE_LOGIN_TYPE);
        redisUtil.expire(CommonConstant.PREFIX_EMPLOYEE_TOKEN + token + "_loginType", JwtUtil.EXPIRE_TIME * 2 / 1000);

        // 获取部门信息
        SysDepart depart = null;
        if (StringUtils.isNotBlank(employee.getDepartId())) {
            depart = sysDepartService.getById(employee.getDepartId());
        }

        // 构建登录信息
        LoginEmployee loginEmployee = new LoginEmployee();
        BeanUtils.copyProperties(employee, loginEmployee);

        // 设置部门名称
        if (depart != null) {
            loginEmployee.setDepartName(depart.getDepartName());
        }

        // 设置登录信息
        loginEmployee.setLoginTime(new Date());
        loginEmployee.setLoginIp(IpUtils.getIpAddr(request));
        loginEmployee.setToken(token);

        // 确保正确设置租户ID，用于后续权限处理
        if (employee.getTenantId() != null) {
            loginEmployee.setTenantId(employee.getTenantId());
        } else {
            // 如果员工没有租户ID，则设置默认值0
            loginEmployee.setTenantId(null);
        }

        // 将登录信息保存到Redis
        redisUtil.set(CommonConstant.PREFIX_EMPLOYEE_INFO + token, JSONObject.toJSONString(loginEmployee));
        redisUtil.expire(CommonConstant.PREFIX_EMPLOYEE_INFO + token, JwtUtil.EXPIRE_TIME * 2 / 1000);

        // 构建返回数据
        JSONObject obj = new JSONObject();
        obj.put("token", token);
        obj.put("employeeInfo", loginEmployee);

        // 确保设置用户名，与管理员登录保持一致
        obj.put("userInfo", loginEmployee);
        obj.put("username", loginEmployee.getUsername());

        // 获取员工权限菜单
        List<JSONObject> permissionMenus = sysPermissionService.getEmployeePermissionByToken(token);
        // 使用与管理员登录一致的菜单字段名
        obj.put("menu", permissionMenus);

        // 获取系统字典
        Map<String, List<DictModel>> sysDict = sysDictService.queryAllDictItems();
        obj.put("sysAllDictItems", sysDict);

        result.setResult(obj);
        result.success("登录成功");

        return result;
    }

    /**
     * App端员工登录
     *
     * @param loginVO
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/mEmployeeLogin", method = RequestMethod.POST)
    @ApiOperation("App端员工登录")
    @SkipTenant("员工登录时跳过租户过滤，避免登录失败问题")
    public Result<JSONObject> mEmployeeLogin(@RequestBody EmployeeLoginVO loginVO, HttpServletRequest request) throws Exception {
        Result<JSONObject> result = new Result<JSONObject>();
        String empNo = loginVO.getEmpNo();
        String password = loginVO.getPassword();

        // 验证参数
        if (StringUtils.isBlank(empNo) || StringUtils.isBlank(password)) {
            result.error500("员工编号或密码不能为空");
            return result;
        }

        // 1. 校验员工是否有效
        QueryWrapper<SysEmployee> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", empNo);
        queryWrapper.eq("status", 1); // 状态为1表示启用
        SysEmployee employee = sysEmployeeService.getOne(queryWrapper);

        if (employee == null) {
            result.error500("员工账号不存在或已禁用");
            return result;
        }

        // 2. 校验密码是否正确
        String userpassword = PasswordUtil.encrypt(empNo, password, employee.getSalt());
        String syspassword = employee.getPassword();
        if (!syspassword.equals(userpassword)) {
            result.error500("员工编号或密码错误");
            return result;
        }

        // 3. 检查员工部门信息
        String departId = employee.getDepartId();
        if (oConvertUtils.isEmpty(departId)) {
            result.error500("员工暂未归属部门，不可登录!");
            return result;
        }

        // 按照web端格式构建登录信息
        return employeeUserInfo(employee, result, request);
    }

    /**
     * 构建员工登录信息 - 参考web端userInfo方法
     * @param employee
     * @param result
     * @param request
     * @return
     */
    private Result<JSONObject> employeeUserInfo(SysEmployee employee, Result<JSONObject> result, HttpServletRequest request) {
        String username = employee.getUsername();
        String syspassword = employee.getPassword();
        
        JSONObject obj = new JSONObject(new LinkedHashMap<>());

        // 生成token - 与web端保持一致
        String token = JwtUtil.sign(username, syspassword);

        // 设置token缓存有效时间
        redisUtil.set(CommonConstant.PREFIX_EMPLOYEE_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_EMPLOYEE_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);

        // 设置登录类型为员工登录
        redisUtil.set(CommonConstant.PREFIX_EMPLOYEE_TOKEN + token + "_loginType", CommonConstant.EMPLOYEE_LOGIN_TYPE);
        redisUtil.expire(CommonConstant.PREFIX_EMPLOYEE_TOKEN + token + "_loginType", JwtUtil.EXPIRE_TIME * 2 / 1000);


        obj.put("token", token);

        // 获取部门信息
        List<SysDepart> departs = new ArrayList<>();
        if (StringUtils.isNotBlank(employee.getDepartId())) {
            SysDepart depart = sysDepartService.getById(employee.getDepartId());
            if (depart != null) {
                departs.add(depart);
                employee.setDepartName(depart.getDepartName());
            }
        }

        obj.put("userInfo", employee);
        
        // 部门信息 - 与web端格式保持一致
        obj.put("departs", departs);
        if (departs.isEmpty()) {
            obj.put("multi_depart", 0);
        } else {
            obj.put("multi_depart", 1);
        }

        // 获取员工权限菜单 - 与web端保持一致的字段名
        try {
            List<JSONObject> permissionMenus = sysPermissionService.getEmployeePermissionByToken(token);
            obj.put("menu", permissionMenus);
        } catch (Exception e) {
            log.warn("获取员工权限菜单失败: {}", e.getMessage());
            obj.put("menu", new ArrayList<>());
        }

        // 获取系统字典 - 与web端保持一致
        Map<String, List<DictModel>> sysDict = sysDictService.queryAllDictItems();
        obj.put("sysAllDictItems", sysDict);

        // 构建LoginEmployee对象并保存到Redis
        LoginEmployee loginEmployee = new LoginEmployee();
        BeanUtils.copyProperties(employee, loginEmployee);
        loginEmployee.setLoginTime(new Date());
        loginEmployee.setToken(token);
        
        if (request != null) {
            loginEmployee.setLoginIp(IpUtils.getIpAddr(request));
        }
        
        if (!departs.isEmpty()) {
            loginEmployee.setDepartName(departs.get(0).getDepartName());
        }

        // 保存员工登录信息到Redis - 使用JSON格式确保兼容性
        redisUtil.set(CommonConstant.PREFIX_EMPLOYEE_INFO + token, JSONObject.toJSONString(loginEmployee));
        redisUtil.expire(CommonConstant.PREFIX_EMPLOYEE_INFO + token, JwtUtil.EXPIRE_TIME * 2 / 1000);

        result.setResult(obj);
        result.success("登录成功");
        return result;
    }

    /**
     * 员工退出登录
     */
    @ApiOperation("员工退出登录")
    @PostMapping("/logout")
    public Result<Object> logout(HttpServletRequest request) {
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (StringUtils.isBlank(token)) {
            return Result.ok("退出登录成功");
        }

        // 清除Redis中的token
        redisUtil.del(CommonConstant.PREFIX_EMPLOYEE_TOKEN + token);
        redisUtil.del(CommonConstant.PREFIX_EMPLOYEE_INFO + token);

        return Result.ok("退出登录成功");
    }

    /**
     * 获取当前登录员工信息
     */
    @ApiOperation("获取当前登录员工信息")
    @GetMapping("/info")
    public Result<LoginEmployee> info(HttpServletRequest request) {
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (StringUtils.isBlank(token)) {
            return Result.error("未找到有效的token");
        }

        // 从Redis中获取员工信息
        Object employeeInfoObj = redisUtil.get(CommonConstant.PREFIX_EMPLOYEE_INFO + token);
        if (employeeInfoObj == null) {
            return Result.error("员工信息已过期，请重新登录");
        }

        String employeeInfoJson = employeeInfoObj.toString();
        if (StringUtils.isBlank(employeeInfoJson)) {
            return Result.error("员工信息已过期，请重新登录");
        }

        LoginEmployee loginEmployee = JSONObject.parseObject(employeeInfoJson, LoginEmployee.class);

        // 不返回密码
        loginEmployee.setPassword(null);

        return Result.ok(loginEmployee);
    }

    /**
     * 获取当前登录员工权限菜单
     */
    @ApiOperation("获取当前登录员工权限菜单")
    @GetMapping("/getPermissionMenus")
    public Result<Map<String, Object>> getPermissionMenus(HttpServletRequest request) {
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (StringUtils.isBlank(token)) {
            return Result.error("未找到有效的token");
        }

        try {
            log.info("开始获取员工权限菜单，token: {}", token);

            // 获取员工权限菜单
            List<JSONObject> permissionMenus = sysPermissionService.getEmployeePermissionByToken(token);
            log.info("获取到员工菜单数量: {}", permissionMenus != null ? permissionMenus.size() : 0);

            // 构造与管理员登录一致的返回结构
            Map<String, Object> resultMap = new HashMap<>();

            // 菜单数据
            resultMap.put("menu", permissionMenus);

            // 权限数据 - 获取所有权限，包括按钮权限
            Set<String> authSet = new HashSet<>();
            Set<String> allAuthSet = new HashSet<>();

            // 查询员工关联的角色
            Object empInfoObj = redisUtil.get(CommonConstant.PREFIX_EMPLOYEE_INFO + token);
            if (empInfoObj != null) {
                String empInfoJson = empInfoObj.toString();
                JSONObject employeeInfo = JSONObject.parseObject(empInfoJson);
                String employeeId = employeeInfo.getString("id");

                if (StringUtils.isNotBlank(employeeId)) {
                    // 查询员工关联的角色
                    List<String> roleIds = sysUserRoleMapper.getRoleIdByUserId(employeeId);
                    if (roleIds != null && roleIds.size() > 0) {
                        for (String roleId : roleIds) {
                            // 查询角色拥有的权限
                            List<SysRolePermission> rolePermissions = sysRolePermissionMapper.selectList(
                                    new QueryWrapper<SysRolePermission>().eq("role_id", roleId));

                            if (rolePermissions != null && rolePermissions.size() > 0) {
                                List<String> permissionIds = rolePermissions.stream()
                                        .map(SysRolePermission::getPermissionId)
                                        .collect(Collectors.toList());

                                // 查询具体权限
                                List<SysPermission> permissions = sysPermissionMapper.selectList(
                                        new QueryWrapper<SysPermission>()
                                                .in("id", permissionIds)
                                                .eq("del_flag", CommonConstant.DEL_FLAG_0));

                                // 收集权限标识
                                for (SysPermission permission : permissions) {
                                    if (permission.getMenuType() == 2) { // 按钮权限
                                        String perms = permission.getPerms();
                                        if (StringUtils.isNotBlank(perms)) {
                                            authSet.add(perms);
                                            allAuthSet.add(perms);
                                        }
                                    } else if (StringUtils.isNotBlank(permission.getName())) {
                                        authSet.add(permission.getName());
                                        allAuthSet.add(permission.getName());
                                    }
                                }
                            }
                        }
                    }
                }
            }

            log.info("获取到员工权限数量: {}", authSet.size());
            resultMap.put("auth", authSet);
            resultMap.put("allAuth", allAuthSet);

            // 系统安全模式
            resultMap.put("sysSafeMode", false);

            return Result.ok(resultMap);
        } catch (Exception e) {
            log.error("获取员工权限菜单失败", e);
            return Result.error("获取权限菜单失败：" + e.getMessage());
        }
    }

    /**
     * 获取系统字典
     */
    @ApiOperation("获取系统字典")
    @GetMapping("/getSysDict")
    public Result<Map<String, List<DictModel>>> getSysDict() {
        Map<String, List<DictModel>> sysDict = sysDictService.queryAllDictItems();
        return Result.ok(sysDict);
    }

    /**
     * 修改员工密码
     */
    @ApiOperation("修改员工密码")
    @PostMapping("/updatePassword")
    public Result<Object> updatePassword(@RequestParam("oldPassword") String oldPassword,
                                         @RequestParam("newPassword") String newPassword,
                                         HttpServletRequest request) {
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (StringUtils.isBlank(token)) {
            return Result.error("未找到有效的token");
        }

        // 从Redis中获取员工信息
        Object employeeInfoObj = redisUtil.get(CommonConstant.PREFIX_EMPLOYEE_INFO + token);
        if (employeeInfoObj == null) {
            return Result.error("员工信息已过期，请重新登录");
        }

        String employeeInfoJson = employeeInfoObj.toString();
        if (StringUtils.isBlank(employeeInfoJson)) {
            return Result.error("员工信息已过期，请重新登录");
        }

        LoginEmployee loginEmployee = JSONObject.parseObject(employeeInfoJson, LoginEmployee.class);

        // 验证旧密码
        SysEmployee employee = sysEmployeeService.getById(loginEmployee.getId());
        if (employee == null) {
            return Result.error("未找到员工信息");
        }

        String salt = oConvertUtils.randomGen(8);
        employee.setSalt(salt);
        String passwordEncode = PasswordUtil.encrypt(employee.getUsername(), newPassword, salt);
        employee.setPassword(passwordEncode);
        boolean success = sysEmployeeService.updateById(employee);
        // 更新密码

        if (success) {
            // 清除Redis中的token和员工信息
            redisUtil.del(CommonConstant.PREFIX_EMPLOYEE_TOKEN + token);
            redisUtil.del(CommonConstant.PREFIX_EMPLOYEE_INFO + token);

            return Result.ok("密码修改成功，请重新登录");
        }else {
            return Result.error("密码修改失败");
        }
    }
}